#pragma once
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <unistd.h>
#include <functional>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unordered_map>

#include "nocopy.hpp"
#include "Log.hpp"
#include "comm.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

static const int default_backlog = 5;
using callback_t = std::function<void(int, InetAddr &)>;

class TcpServer;
using task_t = std::function<void()>;

// class ThreadData
// {
// public:
//     ThreadData(int sockfd, TcpServer *tsp, InetAddr addr)
//         : _sockfd(sockfd), _tsp(tsp), _addr(addr)
//     {
//     }
//     int sockFd()
//     {
//         return _sockfd;
//     }

//     TcpServer *GetTcpSERVER()
//     {
//         return _tsp;
//     }
//     ~ThreadData()
//     {
//         close(_sockfd);
//     }

// private:
//     int _sockfd;
//     TcpServer *_tsp;

// public:
//     InetAddr _addr;
// };


class TcpServer : nocopy
{
public:
    TcpServer(uint16_t port) : _port(port), _isrunning(false)
    {
    }

    void Init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            lg.LogMessage(Fatal, "socket create fail,errno code: %d,error string %s", errno, strerror(errno));
            exit(Socket_error);
        }
        lg.LogMessage(Debug, "linsten_socket create success! linsten_socket:%d", _listensock);

        // 解决绑定失败问题
        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

        // 填充本地网络
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = htons(INADDR_ANY);

        // 绑定到网络
        if (bind(_listensock, CONV(&addr), sizeof(addr)) != 0)
        {
            lg.LogMessage(Debug, "linstsock bind error,errno code:%d,error string:%s", errno, strerror(errno));
            exit(Bind_error);
        }
        lg.LogMessage(Debug, "linsten_sock bind success! sockfd:%d", _listensock);

        // 设置监听
        if (listen(_listensock, default_backlog) != 0)
        {
            lg.LogMessage(Fatal, "listen socket error,error:%d,error string:%s", errno, strerror(errno));
            exit(Listen_error);
        }

        ThreadNs ::ThreadPool<task_t>::GetInstance()->Start();

        // 添加默认任务
        _funcs.insert(std::make_pair("DefaultServer", std::bind(&TcpServer::DefaultServer, this, std::placeholders::_1, std::placeholders::_2)));
    }

    void Start()
    {
        _isrunning = true;
        // 忽略信号  v3
        // signal(SIGCHLD, SIG_IGN);
        while (_isrunning)
        {
            // 接收客户端
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);

            int sockfd = accept(_listensock, CONV(&peer), &len);
            if (sockfd < 0)
            {
                lg.LogMessage(Warning, "accept socket error, errno code: %d, error string: %s", errno, strerror(errno));
                continue;
            }
            lg.LogMessage(Debug, "accept success! get a new sockfd:%d", sockfd);

            // v1单进程版本
            //  Server(sockfd);
            //  close(sockfd);

            // v2多进程
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     lg.LogMessage(Fatal, "fork fail....");
            //     close(sockfd);
            //     continue;
            // }
            // // 子进程
            // else if (id == 0)
            // {
            //     // 关闭描述符，托管进程
            //     close(_listensock);
            //     if (fork() > 0)
            //         exit(0);

            //     Server(sockfd);
            //     close(sockfd);
            //     exit(0);
            // }
            // // 父进程回收，分配任务
            // else
            // {
            //     close(sockfd);
            //     int rid=waitpid(id,nullptr,0);
            //     if(id==rid)
            //     {
            //         //回收资源
            //     }
            // }

            // v3不需要等待
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     lg.LogMessage(Fatal, "fork fail....");
            //     close(sockfd);
            //     continue;
            // }
            // // 子进程
            // else if (id == 0)
            // {
            //     // 关闭描述符，托管进程
            //     close(_listensock);

            //     Server(sockfd);
            //     close(sockfd);
            //     exit(0);
            // }
            // // 父进程回收，分配任务
            // else
            // {
            //     close(sockfd);
            //     //
            // }

            // v4 多线程
            // ThreadData *td = new ThreadData(sockfd, this, peer);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, hundlerQeuest, td);

            // 线程池版本
            // 存在问题 多线程无法并发
            task_t t = std::bind(&TcpServer::Routinue, this, sockfd, peer);

            ThreadNs::ThreadPool<task_t>::GetInstance()->Push(t);
        }
    }

    // static void *hundlerQeuest(void *args)
    // {
    //     // 不关心返回值，将线程分离
    //     pthread_detach(pthread_self());

    //     ThreadData *td = static_cast<ThreadData *>(args);
    //     td->GetTcpSERVER()->Server(td->sockFd(), td->_addr);

    //     delete td;
    //     return nullptr;
    // }

    // 提供服务
    // void Server(int sockfd)
    // {
    //     char buffer[4096];
    //     while (true)
    //     {
    //         int n = read(sockfd, buffer, sizeof(buffer) - 1);
    //         if (n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "client say# " << buffer << std::endl;
    //             std::string server_echo = "server echo:";
    //             server_echo += buffer;
    //             // 转发
    //             int m = write(sockfd, server_echo.c_str(), server_echo.size());
    //         }
    //         else if (n == 0)
    //         {
    //             lg.LogMessage(Info, "client quit...");
    //             break;
    //         }
    //         else
    //         {
    //             lg.LogMessage(Error, "read socket error,code:%d,error string %s", errno, strerror(errno));
    //             break;
    //         }
    //     }
    // }

    void Server(int sockfd, InetAddr addr)
    {
        char buffer[4096];
        while (true)
        {
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                // std::cout << "client say# " << buffer << std::endl;
                std::cout << "[" << addr.PrintDebug() << "]:" << buffer << std::endl;
                std::string server_echo = "server echo:";
                server_echo += buffer;
                // 转发
                int m = write(sockfd, server_echo.c_str(), server_echo.size());
            }
            else if (n == 0)
            {
                lg.LogMessage(Info, "client quit...");
                break;
            }
            else
            {
                lg.LogMessage(Error, "read socket error,code:%d,error string %s", errno, strerror(errno));
                break;
            }
        }
    }

    std::string Read(int sockfd)
    {
        char buffer[4096];

        int n = read(sockfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = 0;
        }
        else if (n == 0)
        {
            lg.LogMessage(Debug, "client quit...,read over");
        }
        else
        {
            lg.LogMessage(Error, "read socket error,code:%d,error string:%s", errno, strerror(errno));
        }
        return buffer;
    }

    void Routinue(int sockfd, InetAddr addr)
    {
        _funcs["DefaultServer"](sockfd, addr);
        std::string type = Read(sockfd);
        lg.LogMessage(Debug, "[%s] select %s ", addr.PrintDebug().c_str(), type.c_str());
        // 心跳相应
        if (type == "ping")
            _funcs[type](sockfd, addr);
        else if (type == "translate")
            _funcs[type](sockfd, addr);
        else if (type == "transform")
            _funcs[type](sockfd, addr);
        else
            {}

        close(sockfd);
    }

    void DefaultServer(int sockfd, InetAddr &addr)
    {
        (void)addr; // 防止编译器告警
        std::string info = "[ ";
        for (auto func : _funcs)
        {
            info += func.first;
            info += " | ";
        }
        info += "]";
        write(sockfd, info.c_str(), info.size());
    }

    // 任务
    void RegisterFunc(const std::string &name, callback_t func)
    {
        _funcs[name] = func;
    }

private:
    uint16_t _port;
    bool _isrunning;
    int _listensock;

    // 业务
    std::unordered_map<std::string, callback_t> _funcs;
};